home *** CD-ROM | disk | FTP | other *** search
- /* ------------------------------------------------------------------------------
-
- FILENAME
- Additions.c
-
- DESCRIPTION
- This file contains the code that creates the graphical effects of the Additions printing
- extension. These routines allow the user to augment pages of a document with additive effects.
- These effects include:
-
- Adding a page border
- Serialize all printed copies
- Add cover page at beginning or end.
-
- These options are configured through a Print dialog panel. The following files
- comprise the Additions printing extension:
-
- Additions.a contains jump table of printing message entry points into the extension
- Additions.c contains the routines that create the additive graphic effects
- Additions.make make file for the Additions printing extension
- Additions.r contains resource definitions for all resources associated with the extension
- Additions.h header file for the Additions.c file
- Utilities.c contains utility routines referenced by all other modules
- Utilities.h header file for the Utilities.c file
- DespoolPageMessage.c contains entry point routine for processing the DespoolPage message
- StartJobMessage.c contains entry point routine for processing the StartJob message
- FinishJobMessage.c contains entry point routine for processing the FinishJob message
- RenderPageMessage.c contains entry point routine for processing the RenderPage message
- PrintDialogMessage.c contains entry point routine for processing the PrintDialog message
-
- The following table summarizes which printing messages the Additions extension supports
- and what "additive effects" it can generate during these messages:
-
- DespoolPage message:
- - adds the page border to the document page
- - creates a serial number text shape to be used for serialization of document pages
- at page rendering time
-
- StartJob message:
- - adds a cover page to the beginning of the document being printed
-
- FinishJob message:
- - adds a cover page to the end of the document being printed
-
- RenderPage message:
- - adds a serial number to the document pages being printed
-
- PrintDialog message:
- - adds the Addition's Print dialog panel to the Print dialog
- - creates, and attaches to the print Job, an Additions collection item which contains
- the specification of the graphic effects the user selected in the Additions dialog panel.
- The format of this collection item is specified by the AdditionsCollection type defined
- in the Additions.h file.
-
- COPYRIGHT
- Copyright Apple Computer, Inc. 1991
- All rights reserved.
-
- INTERFACE ROUTINES
- ComposeCoverPage
- AddPageBorder
- CreateNumberShape
- SerializeCopies
-
- MODIFICATION HISTORY
- 05/15/91 ALA Initial Implementation
-
-
- ------------------------------------------------------------------------------- */
-
- #include <Types.h>
- #include <Quickdraw.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <Dialogs.h>
- #include <TextEdit.h>
- #include <OSUtils.h>
- #include <Packages.h>
- #include <ToolUtils.h>
- #include <Menus.h>
- #include <String.h>
- #include <Strings.h>
- #include <Printing.h>
- #include <FixMath.h>
-
- #include <graphics routines.h>
- #include <graphics libraries.h>
- #include <font routines.h>
- #include <font library.h>
-
- #include <Collections.h>
- #include <Messages.h>
-
- #include <PrintingManager.h>
- #include <PrintingMessages.h>
-
- #include "Utilities.h"
- #include "Additions.h"
-
-
- /*==================================== CONSTANTS ====================================*/
-
-
- /* ======= Misc. Contants ======= */
-
- #define kUserNameStrID -16096 /* Resource ID of system string containing the user's name */
-
-
- /*===================================== INTERNAL ROUTINES =====================================*/
-
-
- /*========================= INTERNAL ROUTINES FOR ADDING A COVER PAGE =========================*/
-
-
- /* ===== AddTextToCover =====
-
- AddTextToCover adds the specified text to the cover page picture and centers the
- text within that picture.
- */
- OSErr AddTextToCover( // (out) Error code
- gxShape coverPage, // (in) picture representing the cover page
- char *textStr, // (in) Text string to add to page (Pascal format)
- gxPoint *where) // (in) Location where to place the text on the page
- {
- OSErr anErr = noErr;
- gxShape aShape;
-
- aShape = GXNewText( Length(textStr), &textStr[1], where);
- if (aShape != nil)
- {
- /* Set the shape's font and size */
- GXSetShapeFont(aShape, FindPNameFont(gxFullFontName, "\pHelvetica"));
- GXSetShapeTextSize(aShape, ff(14));
-
- /* Add the shape to the cover page */
- AddToShape(coverPage, aShape);
- GXDisposeShape(aShape);
- }
- else /* A graphics error occurred creating the shape */
- {
- gxGraphicsError stickyErr;
-
- anErr = GXGetGraphicsError(&stickyErr);
- }
-
- return(anErr);
- }
- /* AddTextToCover */
-
-
- /* ===== AddCoverSplash =====
-
- AddCoverSplash adds a special cover page text message to the top of the page.
- */
- OSErr AddCoverSplash( // (out) Error code
- gxShape coverPage, // (in) picture representing the cover page
- char *textStr, // (in) Text string to add to page (Pascal format)
- gxRectangle *pageRect, // (in) Rectangle representing the cover page
- gxPoint *where) // (in) Location where to place the text on the page
- {
- OSErr anErr = noErr;
- gxShape aShape;
- gxRectangle shapeRect;
-
- aShape = GXNewText( Length(textStr), &textStr[1], where);
- if (aShape != nil)
- {
- /* Set the text's font and size */
- GXSetShapeFont(aShape, FindPNameFont(gxFullFontName, "\pHelvetica"));
- GXSetShapeTextSize(aShape, ff(48));
-
- /* Center the text (left to right) in the page */
- GXGetShapeBounds(aShape, 0, &shapeRect); /* Center the text (left-to-right) in the page */
- GXMoveShapeTo(aShape, FixDiv((pageRect->right - pageRect->left) - (shapeRect.right - shapeRect.left), ff(2)) + pageRect->left, shapeRect.top);
-
- GXSetShapeType(aShape, gxPathType);
- GXSetShapeFill(aShape, gxClosedFrameFill);
-
- AddToShape(coverPage, aShape);
- GXDisposeShape(aShape);
- }
- else
- {
- gxGraphicsError stickyErr;
-
- anErr = GXGetGraphicsError(&stickyErr);
- }
-
- return(anErr);
- }
- /* AddCoverSplash */
-
-
- /*=================== INTERNAL ROUTINES FOR ADDING PAGE BORDER TO DOCUMENT PAGES ===================*/
-
-
- /* ===== RemoveAllShapes =====
-
- RemoveAllShapes removes all shapes from the specified picture.
- */
- void RemoveAllShapes(
- gxShape thePict) // (in) picture whose shapes are to be removed
- {
- gxShape aShape;
- long numShapes;
- gxShapeType theType;
-
- numShapes = GXGetPicture(thePict, nil, nil, nil, nil);
- for (; numShapes > 0; numShapes--)
- {
- GetPictureItem(thePict, 1, &aShape, nil, nil, nil);
- theType = GXGetShapeType(aShape);
-
- if (theType == gxPictureType) /* Call recursively to process this picture */
- {
- RemoveAllShapes(aShape);
- }
- GXDisposeShape( ExtractShape(thePict, 1, 1) );
- }
- }
- /* RemoveAllShapes */
-
-
- /*======================== INTERFACE ROUTINES =======================*/
-
-
- /*========================= INTERFACE ROUTINES FOR ADDING A COVER PAGE =========================*/
-
-
- /* ===== ComposeCoverPage =====
-
- ComposeCoverPage creates a picture which represents the cover page of the printed
- document.
- */
- OSErr ComposeCoverPage( // (out) Error code
- gxShape *coverPage, // (out) picture representing the cover page
- gxFormat theFormat, // (in) Cover page format reference
- gxJobInfo *printerInfo) // (in) Contains info. about the document being printed
- {
- OSErr anErr = noErr;
- gxRectangle pageRect;
- gxPoint where;
- gxGraphicsError stickyErr;
-
- /* Allocate the picture shape that represents the cover page */
- *coverPage = GXNewShape(gxPictureType);
- if (*coverPage == nil)
- {
- anErr = GXGetGraphicsError(&stickyErr);
- goto CantCreateCoverPage;
- }
-
- /* Get the page rectangle from the format */
- GXGetFormatDimensions(theFormat, &pageRect, nil);
-
- /* Make the picture's bounding rectangle = page rectangle, and pin at (0, 0) */
- // GXSetShapeBounds(*coverPage, &pageRect);
- // GXMoveShapeTo(*coverPage, ff(0), ff(0));
-
- /* Create a little splash message */
-
- where.y = pageRect.top + ff(100);
- where.x = pageRect.left + ff(180);
-
- anErr = AddCoverSplash(*coverPage, "\pCover Page", &pageRect, &where);
- if (anErr != noErr)
- {
- goto CantAddCoverSplash;
- }
-
- /* Create the <document name> shape */
-
- where.y += ff(150);
- {
- anErr = AddTextToCover(*coverPage, "\pDocument:", &where);
- if (anErr != noErr)
- {
- goto CantAddDocumentText;
- }
-
- where.x += ff(100);
-
- anErr = AddTextToCover(*coverPage, printerInfo->documentName, &where);
- if (anErr != noErr)
- {
- goto CantAddDocumentName;
- }
- }
-
- /* Create the <application name> shape */
-
- where.y += ff(30);
- where.x = pageRect.left + ff(180);
- {
- anErr = AddTextToCover(*coverPage, "\pApplication:", &where);
- if (anErr != noErr)
- {
- goto CantAddAppText;
- }
-
- where.x += ff(100);
-
- anErr = AddTextToCover(*coverPage, printerInfo->appName, &where);
- if (anErr != noErr)
- {
- goto CantAddAppName;
- }
- }
-
- /* Create the <user name> shape */
-
- where.y += ff(30);
- where.x = pageRect.left + ff(180);
- {
- anErr = AddTextToCover(*coverPage, "\pUser:", &where);
- if (anErr != noErr)
- {
- goto CantAddUserText;
- }
-
- where.x += ff(100);
-
- anErr = AddTextToCover(*coverPage, printerInfo->userName, &where);
- if (anErr != noErr)
- {
- goto CantAddUserNameRsrc;
- }
- }
-
- /* Create the <date> shape */
-
- where.y += ff(30);
- where.x = pageRect.left + ff(180);
- {
- unsigned long secs;
- Str255 s;
-
- anErr = AddTextToCover(*coverPage, "\pDate:", &where);
- if (anErr != noErr)
- {
- goto CantAddDateText;
- }
-
- where.x += ff(100);
-
- GetDateTime(&secs);
- IUDateString(secs, shortDate, s);
-
- anErr = AddTextToCover(*coverPage, s, &where);
- if (anErr != noErr)
- {
- goto CantAddDate;
- }
- }
-
- return(noErr);
-
- /************** Clean-up **************/
-
- CantAddDate:
- CantAddDateText:
- CantAddUserNameRsrc:
- CantAddUserName:
- CantAddUserText:
- CantAddAppName:
- CantAddAppText:
- CantAddDocumentName:
- CantAddDocumentText:
- CantAddCoverSplash:
- GXDisposeShape(*coverPage);
-
- CantCreateCoverPage:
-
- return(anErr);
- }
- /* ComposeCoverPage */
-
-
- /*=================== INTERFACE ROUTINES FOR ADDING PAGE BORDER TO DOCUMENT PAGES ===================*/
-
-
- /* ===== AddPageBorder =====
-
- AddPageBorder adds a border around the entire page and and scales the page to make sure
- all shapes fit within the border. The page to border is specified by the "page" parameter.
-
- To add the page border, the routine performs the following steps:
- 1. Make a copy of the original page shape (newPage variable).
- 2. Scale the newPage shape by approx. 80%.
- 3. Scale any embedded bitmaps in the newPage shape. (graphics didn't handle this before).
- 4. Remove all shapes from the original page shape (page variable).
- 5. Add the newPage shape to the page shape (must preserve the original page referenced passed to us).
- 6. Add the shapes to the page shape which comprise the border.
-
- Note: the original page shape is duplicated because we must scale the contents of the shape,
- but not the shapes which comprise the border. Previously, it didn't work to scale the page down
- and scale the border up so it's bigger.
- */
- OSErr AddPageBorder( // (out) Error code
- gxShape page, // (in) picture for the page being spooled; we'll add a border to it
- gxFormat pageFormat, // (in) Page format record
- Str32 docName) // (in) Name of the document being printed
- {
- OSErr anErr = noErr;
- gxRectangle pageBounds;
- gxPoint pageCenter;
- gxPoint ovalsize;
- gxShape border;
- gxShape newPage;
- gxColor blackBorder;
- gxGraphicsError stickyErr;
- gxShape nameShape;
- gxShape userNameShape;
- gxShape dateShape;
- gxMapping pagemap;
- gxMapping bordermap;
- gxTransform invxform;
-
-
- /* Create a new page shape */
- newPage = page;
-
- /* Get the dimensions of the page so we can determine the center of the page */
- GXGetFormatDimensions(pageFormat, &pageBounds, nil);
- pageCenter.x = ( pageBounds.left + pageBounds.right ) >> 1;
- pageCenter.y = ( pageBounds.top + pageBounds.bottom ) >> 1;
-
- /* Scale the picture by approx. 80% */
- GXGetShapeMapping( newPage, &pagemap );
- ScaleMapping( &pagemap, 0x0000CC11, 0x0000CC11, pageCenter.x, pageCenter.y);
- GXSetShapeMapping( newPage, &pagemap );
- InvertMapping( &bordermap, &pagemap );
-
- anErr = GXGetGraphicsError(&stickyErr);
- if (anErr != noErr)
- {
- goto CantScalePage;
- }
-
- /* Make an inverse transform for the rest of the items that we need to add */
- invxform = GXNewTransform();
- GXSetTransformMapping( invxform, &bordermap );
-
- pageBounds.left += ff(2);
- pageBounds.right -= ff(2);
- pageBounds.top += ff(20);
- pageBounds.bottom -= ff(20);
-
- ovalsize.x = ff(20);
- ovalsize.y = ff(20);
-
- border = NewRoundRect(&pageBounds, &ovalsize);
- anErr = GXGetGraphicsError(&stickyErr);
- if (anErr != noErr)
- {
- goto CantCreateBorderRect;
- }
-
- /* Make sure the round rectangle appears in black */
-
- blackBorder.space = gxGraySpace;
- blackBorder.profile = nil;
- blackBorder.element.gray = 0;
- GXSetShapeColor(border, &blackBorder);
-
- /* Make sure the border fill is correct and is two points wide */
- GXSetShapeFill(border, gxClosedFrameFill);
- GXSetShapePen(border, ff(2));
-
- /* Add the border shape to the page shape */
- GXSetPictureParts( page, 0, 0, 1, &border, nil, nil, &invxform );
- GXDisposeShape(border);
-
- /* Create the header text items; first we add the document name. The document name is centered */
- /* at the top of the border. */
- {
- gxPoint where;
-
- where.y = pageBounds.top - ff(5);
- where.x = pageBounds.left;
-
- nameShape = GXNewText( Length(docName), &docName[1], &where);
- if (nameShape != nil) /* Set the item's font and position it correctly */
- {
- gxRectangle shapeRect;
-
- GXSetShapeFont(nameShape, FindPNameFont(gxFullFontName, "\pSkia Regular"));
- GXSetShapeTextSize(nameShape, ff(12));
- {
- gxFontVariation variations;
-
- variations.name = 'wght';
- variations.value = 0x00028000;
-
- GXSetStyleFontVariations(GXGetShapeStyle(nameShape), 1, &variations);
- }
-
- /* Center the text on the page */
-
- GXGetShapeBounds(nameShape, 0, &shapeRect);
- GXMoveShapeTo(nameShape, FixDiv((pageBounds.right - pageBounds.left) - (shapeRect.right - shapeRect.left), ff(2)) + pageBounds.left, where.y);
-
- /* Add the document name shape to the page */
- GXSetPictureParts( page, 0, 0, 1, &nameShape, nil, nil, &invxform );
- GXDisposeShape(nameShape);
- }
- else
- {
- anErr = GXGetGraphicsError(&stickyErr);
- goto CantCreateDocName;
- }
- }
-
- /* Add the date and time shape to the page */
- {
- gxPoint where;
- Str255 s;
- Str255 dateAndTime;
- unsigned long secs;
-
- /* Form the date/time string */
-
- GetDateTime(&secs);
- iudatestring(secs, shortDate, dateAndTime);
- BlockMove(" @ ", dateAndTime + strlen(dateAndTime), 4 );
-
- iutimestring(secs, false, s);
- BlockMove( s, dateAndTime + strlen(dateAndTime), strlen(s) + 1 );
-
- /* Determine the position of the date/time string and create the text shape */
-
- where.y = pageBounds.top - ff(5);
- where.x = pageBounds.left + ff(20);
-
- dateShape = GXNewText( strlen(dateAndTime), dateAndTime, &where);
- if (dateShape != nil) /* Created the new date item */
- {
- /* Set the font and its size */
- GXSetShapeFont(dateShape, FindPNameFont(gxFullFontName, "\pHelvetica"));
- GXSetShapeTextSize(dateShape, ff(12));
-
- /* Add the date/time shape to the page */
- GXSetPictureParts( page, 0, 0, 1, &dateShape, nil, nil, &invxform );
- GXDisposeShape(dateShape);
- }
- else
- {
- anErr = GXGetGraphicsError(&stickyErr);
-
- GXDisposeShape(nameShape);
-
- goto CantCreateDate;
- }
- }
-
- /* Add the name of the machine on which the page is being printed */
- {
- gxPoint where;
- Str255 s;
- Str255 name;
-
- BlockMove("Printed on ", s, 12);
-
- /* Form the machine name string */
- {
- StringHandle userName;
-
- userName = GetResource('STR ', kUserNameStrID);
- if (userName != nil) /* Got a name of some sort */
- {
- /* Detach and convert to a C string */
- DetachResource((Handle) userName);
- p2cstr(*userName);
-
- if (**userName != '\0') /* Some name is specified */
- {
- BlockMove(*userName, name, strlen(*userName) + 1);
- }
- else /* Zero length name */
- BlockMove("Unknown", name, 8);
-
- /* Dump the storage */
- DisposHandle((Handle) userName);
- }
- else
- BlockMove("Unknown", name, 8);
- }
-
- /* Finish off the rest of the string - concatenate "'s Macintosh" */
- BlockMove(name, s + strlen(s), strlen(name) + 1);
- BlockMove("'s Macintosh", s + strlen(s), 13);
-
- /* Position and allocate the text shape */
-
- where.y = pageBounds.bottom + ff(13);
- where.x = pageBounds.left + ff(20);
-
- userNameShape = GXNewText( strlen(s), s, &where);
- if (userNameShape != nil) /* Created the new date item */
- {
- /* Set the font and text size */
- GXSetShapeFont(userNameShape, FindPNameFont(gxFullFontName, "\pSkia Regular"));
- GXSetShapeTextSize(userNameShape, ff(12));
-
- /* Add the name shape to the page */
- GXSetPictureParts( page, 0, 0, 1, &userNameShape, nil, nil, &invxform );
- GXDisposeShape(userNameShape);
-
- {
- gxFontVariation variations;
-
- variations.name = 'wght';
- variations.value = 0x00004000;
-
- GXSetStyleFontVariations(GXGetShapeStyle(userNameShape), 1, &variations);
- }
-
- }
- else
- {
- anErr = GXGetGraphicsError(&stickyErr);
-
- GXDisposeShape(nameShape);
- GXDisposeShape(dateShape);
-
- goto CantCreateUserName;
- }
- }
-
- GXDisposeTransform( invxform );
- return(noErr);
-
- /**************** Clean-up ****************/
-
- CantScalePage:
- CantCreateBorderRect:
- CantCopyPageShape:
- CantCreateDocName:
- CantCreateDate:
- CantCreateUserName:
-
- return(anErr);
- }
- /* AddPageBorder */
-
-
- /*======================== INTERFACE ROUTINES FOR SERIALIZING DOCUMENT PAGES =======================*/
-
-
- /* ===== SerializeCopies =====
-
- SerializeCopies adds the serial number to each page which is printed.
- */
- void SerializeCopies( // (out) Error code
- gxShape page, // (in) picture for the page being spooled
- gxFormat pageFormat, // (in) Page format record
- long currCopyNum, // (in) Current copy of the document being printed (relative to beginning of the job)
- Boolean *pageChanged, // (out) True if a copy of a page has changed; otherwise ignored
- long nextEndSerialNum, // (in) last serial number in the batch being printed
- long numCopies) // (in) number of copies being printed
- {
- gxRectangle pageRect; // rectangle for the page.
- gxPoint where; // location of the stamp on the page.
- fixed dx, dy,
- cx, cy;
- gxPoint shapeCenter;
- Str31 copyNumber;
- gxRectangle shapeRect;
- fixed sx;
- fixed sy;
- fixed scale;
-
- /* First remove the last serial number shape which was added to the page the last */
- /* time the page was rendered. */
- if (gSerialShape != nil)
- {
- short i;
- short numPictItems;
-
- numPictItems = GXGetPicture(page, nil, nil, nil, nil);
-
- for (i = 1; i <= numPictItems; i++)
- {
- gxShape aShape;
-
- (void) GetPictureItem(page, i, &aShape, nil, nil, nil);
-
- if (gSerialShape == aShape) /* The last serial number is already in the page; remove it */
- {
- GXSetPictureParts(page, i, 1, 0, nil, nil, nil, nil);
- break;
- }
- }
- }
-
- GXGetFormatDimensions(pageFormat, &pageRect, nil);
-
- where.x = pageRect.left;
- where.y = pageRect.bottom;
-
- dx = pageRect.right - pageRect.left;
- dy = pageRect.top - pageRect.bottom;
-
- cx = FixDiv(dx, ff(2)) + pageRect.left;
- cy = FixDiv(dy, ff(2)) + pageRect.bottom;
-
- /* Compute the correct copy number and place string in the copyShape */
- numtostring(nextEndSerialNum - numCopies + currCopyNum, copyNumber);
- gSerialShape = GXNewText(strlen(copyNumber), copyNumber, &where);
-
- /* Set the text shape's font and size */
- GXSetShapeFont(gSerialShape, FindPNameFont(gxFullFontName, "\pHelvetica"));
- GXSetShapeTextSize(gSerialShape, ff(48));
-
- /* Center the shape on the page */
- GXGetShapeCenter(gSerialShape, 0, &shapeCenter);
- GXMoveShape(gSerialShape, cx - shapeCenter.x, cy - shapeCenter.y);
-
- /* Draw the shape as an outline */
-
- GXSetShapeType(gSerialShape, gxPathType);
- GXSetShapeFill(gSerialShape, gxClosedFrameFill);
- GXSetShapePen(gSerialShape, 0x00005000);
-
- /* Now scale it so it fills most of the page */
- {
- gxTransform theTransform;
-
- GXGetShapeBounds(gSerialShape, 0, &shapeRect);
- sx = FixDiv(dx, shapeRect.right - shapeRect.left);
- sy = FixDiv(dy, shapeRect.top - shapeRect.bottom);
-
- if (sx < sy)
- scale = sx;
- else
- scale = sy;
-
- scale = FixMul(scale, 0x0000B500); // use 70% of the scale value;
-
- theTransform = GXGetShapeTransform(gSerialShape);
-
- GXScaleTransform(theTransform, scale, scale, cx, cy);
- }
-
- /* Add the shape to the page and dispose of the local copy of the shape. Also, */
- /* save its reference so we can delete it the next time we add a serial number */
- /* shape to this rendered page. */
-
- InsertPictureItem(page, 0, gSerialShape, nil, nil, nil);
- GXDisposeShape(gSerialShape);
-
- (void) GetPictureItem(page, GXGetPicture(page, nil, nil, nil, nil), &gSerialShape, nil, nil, nil);
-
- /* Indicate we've changed a copy of the page */
- *pageChanged = true;
- }
- /* SerializeCopies */
-